package cn.e4j.core.quartz;

import cn.e4j.core.util.AppCxt;
import cn.e4j.core.util.SpringContextHolder;
import cn.e4j.modular.system.entity.SysTask;
import org.quartz.*;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.TriggerBuilder.newTrigger;

/**
 * 定时器工具类
 */
public class QuartzUtil {

    private QuartzUtil() {
    }

    /**
     * 任务调度参数key
     */
    public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";

    private static final String SCHEDULE_NAME = "HUSKY_";

    /**
     * 触发器 KEY
     */
    public static TriggerKey getTriggerKey(String jobId) {
        return TriggerKey.triggerKey(SCHEDULE_NAME + jobId);
    }

    /**
     * 定时器 Key
     */
    public static JobKey getJobKey(String jobId) {
        return JobKey.jobKey(SCHEDULE_NAME + jobId);
    }

    /**
     * 判断定时器 是否执行？？？？
     */
    public static boolean checkJobKey(Scheduler scheduler, String jobId) {
        try {
            return scheduler.checkExists(getJobKey(SCHEDULE_NAME + jobId));
        } catch (SchedulerException e) {
            throw new RuntimeException("checkExists Fail", e);
        }
    }

    /**
     * 表达式触发器
     */
    public static CronTrigger getCronTrigger(Scheduler scheduler, String jobId) {
        try {
            return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
        } catch (SchedulerException e) {
            throw new RuntimeException("getCronTrigger Fail", e);
        }
    }

    /**
     * 创建定时器
     */
    public static void createJob(Scheduler scheduler, SysTask sysTask, Map<String, String> inDto) {
        try {

            if (null != getCronTrigger(scheduler, sysTask.getTASK_CLASS())) {
                QuartzUtil.resumeJob(scheduler, sysTask.getTASK_CLASS());
            } else {

                // 构建定时器
                JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) SpringContextHolder.getBean(sysTask.getTASK_CLASS()).getClass())
                        .withIdentity(getJobKey(sysTask.getTASK_CLASS()))
                        .build();

                CronScheduleBuilder scheduleBuilder = cronSchedule(sysTask.getTASK_RULE())
                        .withMisfireHandlingInstructionDoNothing();

                //System.out.println(sysTask.getTASK_RULE());

                CronTrigger trigger = TriggerBuilder.newTrigger()
                        .withIdentity(getTriggerKey(sysTask.getTASK_CLASS()))
                        .withSchedule(scheduleBuilder)
                        //.withSchedule(cronSchedule(sysTask.getTASK_RULE()))
                        .build();

                jobDetail.getJobDataMap().put(JOB_PARAM_KEY, inDto);
                scheduler.scheduleJob(jobDetail, trigger);
                // 如果该定时器处于暂停状态
                if (sysTask.getTASK_STATUS().equals("0")) {
                    pauseJob(scheduler, sysTask.getTASK_CLASS());
                }
            }
        } catch (SchedulerException e) {
            throw new RuntimeException("createJob Fail", e);
        }
    }

    /**
     * 更新定时任务
     */
    public static void updateJob(Scheduler scheduler, SysTask sysTask) {
        try {

            if (null != getCronTrigger(scheduler, sysTask.getTASK_CLASS())) {
                // 构建定时器
                TriggerKey triggerKey = getTriggerKey(sysTask.getTASK_CLASS());
                CronScheduleBuilder scheduleBuilder = cronSchedule(sysTask.getTASK_RULE())
                        .withMisfireHandlingInstructionDoNothing();
                CronTrigger trigger = getCronTrigger(scheduler, sysTask.getTASK_CLASS());
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
                trigger.getJobDataMap().put(JOB_PARAM_KEY, sysTask);
                scheduler.rescheduleJob(triggerKey, trigger);

                // 如果该定时器处于暂停状态
                if (sysTask.getTASK_STATUS().equals("0")) {
                    pauseJob(scheduler, sysTask.getTASK_CLASS());
                }
            }
        } catch (SchedulerException e) {
            throw new RuntimeException("updateJob Fail", e);
        }
    }

    /**
     * 停止定时器
     */
    public static void pauseJob(Scheduler scheduler, String jobId) {
        try {
            scheduler.pauseJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            throw new RuntimeException("pauseJob Fail", e);
        }
    }

    /**
     * 恢复定时器
     */
    public static void resumeJob(Scheduler scheduler, String jobId) {
        try {
            scheduler.resumeJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            throw new RuntimeException("resumeJob Fail", e);
        }
    }

    /**
     * 删除定时器
     */
    public static void deleteJob(Scheduler scheduler, String jobId) {
        try {
            scheduler.deleteJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            throw new RuntimeException("deleteJob Fail", e);
        }
    }

    /**
     * 立即执行定时器
     */
    public static void run(Scheduler scheduler, SysTask sysTask, Map<String, String> params) {
        try {

            if (null == getCronTrigger(scheduler, sysTask.getTASK_CLASS())) {
                QuartzUtil.createJob(scheduler, sysTask, params);
            }
            JobDataMap dataMap = new JobDataMap();
            dataMap.put(JOB_PARAM_KEY, params);
            scheduler.triggerJob(getJobKey(sysTask.getTASK_CLASS()), dataMap);

        } catch (SchedulerException e) {
            throw new RuntimeException("run Fail", e);
        }
    }

    /**
     * 执行一次定时器
     */
    public static void runOnce(Scheduler scheduler, SysTask sysTask, Map<String, String> params) {

        //唯一ID
        String run_id = System.currentTimeMillis()+"";

        try {

            // 构建定时器
            JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) SpringContextHolder.getBean(sysTask.getTASK_CLASS()).getClass())
                    .withIdentity(getJobKey(sysTask.getTASK_CLASS()))
                    .build();

            SimpleTrigger trigger = newTrigger().withIdentity(getTriggerKey(run_id))
                    .startAt(new Date()).withSchedule(SimpleScheduleBuilder.simpleSchedule()
                            .withIntervalInSeconds(0)
                            .withRepeatCount(0))//重复执行的次数，因为加入任务的时候马上执行了，所以不需要重复，否则会多一次。
                    .build();
            scheduler.scheduleJob(jobDetail, trigger);

        } catch (SchedulerException e) {
            throw new RuntimeException("run Fail", e);
        }finally {
            deleteJob(scheduler, run_id);
        }
    }


}
